﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using Fujitsu.JiraAnalysis.Common;
using System.Data.Objects;

namespace Fujitsu.JiraAnalysis.DAL
{
    public class IssueStorage
    {
        public IEventLog eventLog = new EventLogWrapper();

        public List<Issue> GetProjectIssues(int projectId)
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                return (from i in db.Issue
                        where i.ProjectID == projectId
                        select i).ToList();
            }
        }

        public void UpdateIssue(Issue issue)
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                var issueToUpdate = db.Issue.FirstOrDefault(i => i.ID == issue.ID);

                if (issueToUpdate != null)
                {
                    issueToUpdate.ReporterID = issue.ReporterID;
                    issueToUpdate.AssigneeID = issue.AssigneeID;
                    issueToUpdate.TypeID = issue.TypeID;
                    issueToUpdate.Summary = issue.Summary;
                    issueToUpdate.Description = issue.Description;
                    issueToUpdate.PriorityID = issue.PriorityID;
                    issueToUpdate.ResolutionID = issue.ResolutionID;
                    issueToUpdate.StatusID = issue.StatusID;
                    issueToUpdate.Created = issue.Created;
                    issueToUpdate.Updated = issue.Updated;
                    issueToUpdate.Duedate = issue.Duedate;
                }

                db.SaveChanges();
            }
        }

        public int GetTypeId(int projectId, int jiraTypeId)
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                return (from t in db.IssueTypeMapping
                        where t.ProjectID == projectId && t.JiraTypeID == jiraTypeId
                        select t.TypeID).FirstOrDefault();
            }
        }

        public int GetPriorityId(int projectId, int jiraPriorityId)
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                return (from t in db.PriorityMapping
                        where t.ProjectID == projectId && t.JiraPriorityID == jiraPriorityId
                        select t.PriorityID).FirstOrDefault();
            }
        }

        public int? GetResolutionId(int projectId, int jiraResolutionId)
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                try
                {
                    return (from t in db.ResolutionMapping
                            where t.ProjectID == projectId && t.JiraResolutionID == jiraResolutionId
                            select t.ResolutionID).First();
                }
                catch (InvalidOperationException)
                {
                    return null;
                }
            }
        }

        public int GetStatusId(int projectId, int jiraStatusId)
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                return (from t in db.StatusMapping
                        where t.ProjectID == projectId && t.JiraStatusID == jiraStatusId
                        select t.StatusID).FirstOrDefault();
            }
        }

        public int? AddIssue(Issue dbIssue)
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                try
                {
                    db.AddToIssue(dbIssue);
                    db.SaveChanges();
                }
                catch (OptimisticConcurrencyException)
                {
                    db.Refresh(RefreshMode.ClientWins, dbIssue);
                    db.SaveChanges();
                }
                catch (DataException ex)
                {
                    EventLogger.CreateInstance(eventLog).LogWriteError(string.Concat("Can't add issue to DB.", Environment.NewLine, ex.StackTrace));
                    return null;
                }

                return dbIssue.ID;
            }
        }

        public void DeleteIssue(int issueId)
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                var dbWorklogs = db.Worklog.Where(w => w.IssueID == issueId);
                var worklogStorage = new WorklogStorage();
                foreach (var dbWorklog in dbWorklogs)
                {
                    worklogStorage.DeleteWorklog(dbWorklog.ID);
                }

                var fixVersions = db.FixVersion.Where(v => v.IssueID == issueId);
                var fixVersionStorage = new FixVersionStorage();
                foreach (var fixVersion in fixVersions)
                {
                    fixVersionStorage.DeleteFixVersion(fixVersion.IssueID, fixVersion.VersionID);
                }
            }
            using (var db = new JiraAnalysisDBEntities())
            {
                var dbIssue = db.Issue.FirstOrDefault(w => w.ID == issueId);
                if (dbIssue != null)
                {
                    try
                    {
                        db.Issue.DeleteObject(dbIssue);
                        db.SaveChanges();
                        EventLogger.CreateInstance(eventLog).LogWrite(string.Format("Issue '{0}' (JiraKey: '{1}') was deleted from '{2}' project with related items.", dbIssue.ID, dbIssue.IssueKey, dbIssue.ProjectID));
                    }
                    catch (OptimisticConcurrencyException)
                    {
                        db.Refresh(RefreshMode.ClientWins, dbIssue);
                        db.SaveChanges();
                    }
                    catch (DataException ex)
                    {
                        EventLogger.CreateInstance(eventLog).LogWriteError(string.Concat("Can't delete issue from DB.", Environment.NewLine, ex.StackTrace));
                    }
                }
            }
        }

        public void DeleteIssuesOfProject(int projectId)
        {
            var issues = GetProjectIssues(projectId);
            foreach (var issue in issues)
            {
                DeleteIssue(issue.ID);
            }
        }

        public Issue GetIssue(int projectId, string issueKey)
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                return db.Issue.FirstOrDefault(issue => issue.ProjectID == projectId && issue.IssueKey == issueKey);
            }
        }

        public IEnumerable<int> GetIssueIdsToBeDeleted(int projectId, List<string> jiraIssueKeys)
        {
            using (var db = new JiraAnalysisDBEntities())
            {
                var issues = db.Issue.Where(i => i.ProjectID == projectId).ToList();
                foreach (var issue in issues)
                {
                    if (!jiraIssueKeys.Contains(issue.IssueKey))
                        yield return issue.ID;
                }
            }
        }
    }
}
